- 
                Notifications
    
You must be signed in to change notification settings  - Fork 169
 
Enable optimistic search to memory optimized search. #2933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable optimistic search to memory optimized search. #2933
Conversation
        
          
                src/main/java/org/opensearch/knn/index/query/nativelib/NativeEngineKnnVectorQuery.java
          
            Show resolved
            Hide resolved
        
      | 
           @Vikasht34 @shatejas  | 
    
| 
           Will look into this PR :- Tomorrow Morning  | 
    
5b006af    to
    1e09bf0      
    Compare
  
    | ); | ||
| } | ||
| 
               | 
          ||
| /* | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic has been moved to approximateSearch
| * An immutable, empty {@link BitSet} implementation used to represent | ||
| * the absence of filter bits without incurring null checks or allocations. | ||
| */ | ||
| public static final BitSet MATCH_ALL_BIT_SET = new BitSet() { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious why we are not uysing Lucene's MathAllBits or MatcNoBits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could not use both, as it's sub class of Bits while we need BitSet in here. 😵💫
Since optimistic search will call approximateSearch twice, we need to keep BitSet for reusing.
| } | ||
| 
               | 
          ||
| @Override | ||
| public int length() { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we doing any iteration on Bitset , this gooona break if we are doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only place using this one is when we're getting siblings in nested case.
In there, we don't do iteration.
          
 There are caveats to doing this, 
 I think 1 is a concern which needs discussion, 2 is manageable with some extra logic to keep behavior consistent, 3 isn't a big deal  | 
    
          
 @shatejas from a user perspective all of this is a breaking change if we are making Lucene on Faiss default. So this needs to be documented in the docs to clearly callout the behavior and how to mitigate this. Along with this, we should ensure that older indices are still on the same non memory optimized based search so that upgrades are seamless. We have already seen GH issues in part where changes in range of cosine scores lead to issues with users. #2561  | 
    
        
          
                ...java/org/opensearch/knn/index/query/memoryoptsearch/optimistic/Optimistic2ndSearchUtils.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      | @Setter | ||
| private KnnCollectorManager optimistic2ndKnnCollectorManager; | ||
| 
               | 
          ||
| public static class OptimisticKnnCollectorManager implements KnnCollectorManager { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we move this to a separate file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, will update in the next rev.
| public PerLeafResult(final Bits filterBits, final TopDocs result) { | ||
| this.filterBits = filterBits == null ? new Bits.MatchAllBits(0) : filterBits; | ||
| // Indicates whether this result was produced via exact or approximate search. | ||
| private final SearchMode searchMode; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the use of this parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimistic search would do deep dive HNSW search with acquired top k results as seeds. And this will not be needed if the results acquired via exact search. Hence having search mode here, and let it bypass the second search if possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cases when results will be acquired from exact search is the filters case right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! Whenever running exact search for whatever reason, it will set the mode as EXACT_SEARCH.
If that's the case, then we should not run 2nd search as it's pointless.
| * An immutable, empty {@link BitSet} implementation used to represent | ||
| * the absence of filter bits without incurring null checks or allocations. | ||
| */ | ||
| public static final BitSet MATCH_ALL_BIT_SET = new BitSet() { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
| * @return a {@link TopDocs} object containing the top {@code k} approximate search results | ||
| * @throws IOException if an error occurs while reading index data or accessing vector fields | ||
| */ | ||
| public TopDocs approximateSearch( | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why we are making this function public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need this particular function in optimistic second search. Otherwise, if using searchLeaf, then we will end up building filter bitset twice.
| 
           We are brining in a lot of code from Lucene. Please mention the source of the code for better maintainability. One way I would think is to move the class to   | 
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks Good !! Clean Code and Very Concise !! Thanks
e625f04    to
    0cc0b54      
    Compare
  
    | /** | ||
| * A special flag used for testing purposes that forces execution of the second (exact) search | ||
| * in optimistic search mode, regardless of the results returned by the first approximate search. | ||
| * <p> | ||
| * This flag should never be enabled in production; it is intended for testing and debugging only. | ||
| */ | ||
| private static final boolean FORCE_REENTER_TESTING; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets remove this in next iteration of PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed for testing the second reentrance in optimistic search.
It's bit tricky to make the data to ensure there's at least one segment whose min topk score is greater than the minimum score in the merged top-k results
The base branch was changed.
ea03c31    to
    21aa301      
    Compare
  
            
          
                src/main/java/org/opensearch/knn/index/query/memoryoptsearch/MemoryOptimizedKNNWeight.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                src/main/java/org/opensearch/knn/index/query/memoryoptsearch/MemoryOptimizedKNNWeight.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      23325ed    to
    0f44ba7      
    Compare
  
    There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall, some minor comments
        
          
                src/main/java/org/opensearch/knn/index/query/memoryoptsearch/MemoryOptimizedKNNWeight.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                src/main/java/org/opensearch/knn/index/query/nativelib/NativeEngineKnnVectorQuery.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                src/main/java/org/opensearch/knn/index/query/nativelib/NativeEngineKnnVectorQuery.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      | final PerLeafResult perLeafResult = perLeafResults.get(i); | ||
| final TopDocs perLeaf = perLeafResults.get(i).getResult(); | ||
| if (perLeaf.scoreDocs.length > 0 && perLeafResult.getSearchMode() == PerLeafResult.SearchMode.APPROXIMATE_SEARCH) { | ||
| if (FORCE_REENTER_TESTING || perLeaf.scoreDocs[perLeaf.scoreDocs.length - 1].score >= minTopKScore) { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Its not ideal to have a testing flag in final code, can't we create a test case where we mock scores?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since whether if it kicks off the second search will be entirely depending on data. Which is hard to be made, and this was the only solution I found so far to always enforce it to enter 2nd search in optimistic.
        
          
                src/main/java/org/opensearch/knn/index/query/nativelib/NativeEngineKnnVectorQuery.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                src/main/java/org/opensearch/knn/index/query/nativelib/NativeEngineKnnVectorQuery.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      0f44ba7    to
    4410b34      
    Compare
  
    | 
           @0ctopus13prime any reason why MacOS builds are failing?  | 
    
| 
           @navneet1v  | 
    
4410b34    to
    0800030      
    Compare
  
    …pensearch-project#2904) Signed-off-by: Dooyong Kim <[email protected]>
Signed-off-by: Dooyong Kim <[email protected]>
0800030    to
    a43fa59      
    Compare
  
            
          
                src/main/java/org/opensearch/knn/index/query/nativelib/NativeEngineKnnVectorQuery.java
          
            Show resolved
            Hide resolved
        
      Signed-off-by: Dooyong Kim <[email protected]>
a43fa59    to
    347347f      
    Compare
  
    a95a7d0
      into
      
  
    opensearch-project:main
  
    * Added MMapByteVectorValues for FP16 native scoring in LuceneOnFaiss. (#2904) Signed-off-by: Dooyong Kim <[email protected]> * Enable optimistic search for LuceneOnFaiss. Signed-off-by: Dooyong Kim <[email protected]> * Added debug logging, measure execution times of 2nd search. Signed-off-by: Dooyong Kim <[email protected]> --------- Signed-off-by: Dooyong Kim <[email protected]> (cherry picked from commit a95a7d0)
* Added MMapByteVectorValues for FP16 native scoring in LuceneOnFaiss. (#2904) Signed-off-by: Dooyong Kim <[email protected]> * Enable optimistic search for LuceneOnFaiss. Signed-off-by: Dooyong Kim <[email protected]> * Added debug logging, measure execution times of 2nd search. Signed-off-by: Dooyong Kim <[email protected]> --------- Signed-off-by: Dooyong Kim <[email protected]>
* Added MMapByteVectorValues for FP16 native scoring in LuceneOnFaiss. (#2904) * Enable optimistic search for LuceneOnFaiss. * Added debug logging, measure execution times of 2nd search. --------- Signed-off-by: Dooyong Kim <[email protected]> Co-authored-by: Doo Yong Kim <[email protected]>
Description
RFC : #2924
Enable optimistic search for memory optimized search and deprecate MultiLeafKnnCollector which has an early termination logic.
This PR has three big changes:
Now, when memory-optimized search is enabled, all queries use
NativeEngineKnnVectorQuery.KnnQuery, which only provides aScorerSupplierand performs search within a single leaf segment (with the resultingScorerbeing consumed by an externalBulkScorerunder the standard Lucene search flow). But optimistic search requires coordination across segments. It needs to run an initial (first-phase) search, then identify and revisit only the segments likely to contain promising results.To support this coordinated two-phase process,
NativeEngineKnnVectorQueryis a more suitable entry point thanKnnQuery.Backported Lucene components required for optimistic search, specifically:
2.1. ReentrantKnnCollectorManager
2.2. SeededMappedDISI
2.3. SeededTopDocsDISI
Related Issues
Resolves #[Issue number to be closed when this PR is merged]
#2924
Check List
--signoff.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.